/**
 * 
 */
use std::fmt::Display;
use std::fmt;
struct Box{vol: u32}
struct Tube{x:u32,y:u32, z:u32,vol: u32}

trait Brush{fn draw(&self);}
impl Brush for Box{
    fn draw(&self){
        println!("draw box");
    }
}
impl Brush for Tube{
    fn draw(&self){
        println!("{}",self);
    }
}

impl Display for Tube{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,"x:{},y:{},z:{}.体积={}",self.x,self.y,self.z,self.vol)
    }
}

fn draw_objet(b1:&impl Brush, b2:&impl Brush){b1.draw();b2.draw();}
fn draw_objet2<T:Brush>(b1:&T, b2:&T){b1.draw();b2.draw();}
//+的第一个形式：在参数中书写
fn draw_ojbect3(shape:&(impl Brush+Display)){
    shape.draw();
}
//+的第二个形式：在方法名后书写
fn draw_object4<T:Brush+Display>(shape:&T){
    shape.draw();
}
//+的第三个形式：使用where字句
fn draw_ojbect31<T>(shape:&T)
where T:Display+Brush
{
    shape.draw();
}

//返回一个接口特质，可惜由于这个接口特质有许多实现结构，结果编译编译器不无法知道具体结构类型
fn create_shape(px:u32,py:u32,pz:u32)->impl Brush{
    Tube{
        x:px,
        y:py,
        z:pz,
        vol:px*py*pz
    }
}

fn main() {
    let b1 = Box{vol: 20};
    let t1 = Tube{x:5, y:3, z:4, vol: 60};
    let t2=  Tube{x:10,y:8,z:3,vol:210};
    draw_objet(&b1,&t1);
    //draw_objet2(&b1,&t1);//这样会报错的，因为draw_objet2函数要求参数类型必须一致
    draw_objet2(&t1,&t2);
    //
    //draw_ojbect3(&b1);  //这个明显是错误的，因为要求，因为drawo_ojbect3要求参数必须实现两个接口特质
    draw_ojbect3(&t1);
    draw_object4(&t1);
    draw_ojbect31(&t2);

    let my_tube=create_shape(10,20,40);
    //println!("{}",my_tube.vol);  // 这样会报错，因为编译器无法指导my_tube具体类型
    my_tube.draw();  //但这个可以的。 所以能不能知道，全看编译器或者是rust发明人的意愿了。

    let my_tube2=create_shape2(19,23,22);
    //my_tube2.draw();  //这个也不行，因为不认为是Tube，只认接口特质
}


trait IsShape{fn is(&self)->bool;}
impl IsShape for Tube{
    fn is(&self)->bool{
        return true;
    }
}
/**
 * 返回特质作为参数，但是编译器并不知道具体类型
 */
fn create_shape2(px:u32,py:u32,pz:u32)->impl IsShape{
    Tube{
        x:px,
        y:py,
        z:pz,
        vol:px*py*pz
    }
}